<?php
/*
 * SoloPHP PHP框架
 * $Author: Yotianya <yotianya@gmail.com>
 * $Dtime:2011-10-24
 * $Copyright: CopyRight By SoloPHP Yotianya
 */


class Model {

	public $db;					//数据库驱动类
	public $table;				//表名称
	public $tablename = null;	//表全名
	public $pk;  				//表主键


	/**
	 * 构造函数
	 */
	public function __construct(){

		if( null == $this->tablename )$this->tablename = $GLOBALS['C']['DB']['DBprefix'] . $this->table;
		$this->db = newClass($GLOBALS['C']['DB']['DBtype']);
	}

	/**
	 * 魔术函数，执行模型扩展类的自动加载及使用
	 */
	public function __call($name, $args){

		if(in_array($name,array('Pager','Cache'))){
			return newClass($name)->__input($this, $args);
		}elseif(!method_exists( $this, $name )){
			errorMsg('',"方法 {$name} 未定义");
		}
	}


	/**
	 *escapes():过滤数据
	 */
	public function escapes($value){
		if(is_null($value))return 'NULL';
		if(is_bool($value))return $value ? 1 : 0;
		if(is_int($value))return (int)$value;
		if(is_float($value))return (float)$value;
		if(@get_magic_quotes_gpc())$value = stripslashes($value);
		return '\''.mysql_real_escape_string($value, $this->conn).'\'';
	}
	/**
	 * getOne():获取一条记录的公共方法
	 * @param $id  主键等于$id的条件
	 */
	public function findOne($Pk){
		$Pk = $this->db->escape($Pk);
		$sql="select * from `$this->tablename` ";
		( null != $Pk)?$where = "where `$this->pk`='$Pk'": $where = null;
		$sql .= $where;
		$sql = $this->db->setlimit($sql, 1);
		if($record = $this->db->getArray($sql)){
			return array_pop($record);
		}else{
			return FALSE;
		}

	}

	/**
	 * getAll():获取全部记录的公共方法
	 * @param $sort  排序
	 * @param $limit 数量
	 */
	public function findAll($sort =null,$limit = null){
		
		if(null != $sort){
			$sort = $sort;
		}else{
			$sort = $this->pk;
		}
		$sql="select * from `$this->tablename` ORDER BY $sort";
		if(null != $limit)$sql = $this->db->setlimit($sql, $limit);
		return $this->db->getArray($sql);
	}
	/**
	 * 计算符合条件的记录数量
	 */
	public function findCount(){
		$sql = "SELECT COUNT($this->pk) AS SP_COUNTER FROM `$this->tablename`";
		$result = $this->db->getArray($sql);
		return $result[0]['SP_COUNTER'];
	}
	/**
	 * add():添加记录
	 * @param row   添加信息
	 */
	public function add($row){

		if(!is_array($row))return FALSE;
		$row = $this->formatRow($row);
		if(empty($row))return FALSE;
		foreach($row as $key => $value){
			$cols[] = '`'.$key.'`';
			$vals[] = $this->db->escape($value);
		}
		$col = implode(',', $cols);
		$val = implode(',', $vals);

		$sql = "INSERT INTO `$this->tablename` ($col) VALUES ($val)";// 获取当前新增的ID
		if(FALSE != $this->db->exec($sql)){
			return $this->db->newinsertid();
		}
		return FALSE;

	}

	/**
	 * update():修改记录
	 * @param row   修改信息
	 */
	public function update($row,$Pk){
		$Pk = $this->db->escape($Pk);
		$row = $this->formatRow($row);
		if(empty($row))return FALSE;
		foreach($row as $key => $value){
			$value = $this->db->escape($value);
			$vals[] = "$key = $value";
		}
		$values = implode(", ",$vals);
		$sql = "UPDATE `$this->tablename` SET $values where `$this->pk`='$Pk'";
		return $this->db->exec($sql);
	}
	/**
	 * plusNum():记录自加
	 * $field   自加字段
	 * $num     自加数目
	 */
	 public function plusNum($Pk,$field,$num=1){
		$Pk = $this->db->escape($Pk);
		$sql = "UPDATE `$this->tablename` SET `$field` = `$field`+$num where `$this->pk`='$Pk'";
		return $this->db->exec($sql);
		 }
	/**
	 * subNum():记录自减
	 * $field   自减字段
	 * $num     自减数目
	 */
	 public function subNum($Pk,$field,$num=1){
		$Pk = $this->db->escape($Pk);
		$sql = "UPDATE `$this->tablename` SET `$field` = `$field`-$num where `$this->pk`='$Pk'";
		return $this->db->exec($sql);
		 }


	/**
	 * del():删除记录
	 * @param $condition  where条件   可以为数组array(id=>1,name=>2)也可以为字符串'`id`=1 And `name`=2'
	 */
	public function del($conditions){
		$where = "";
		if(is_array($conditions)){
			$join = array();
			foreach( $conditions as $key => $condition ){
				$condition = $this->db->escape($condition);
				$join[] = "`$key` = $condition";
			}
			$where = "WHERE ".implode(" AND ",$join);
		}else{
			if(null != $conditions)$where = "WHERE $conditions";
		}
		$sql = "DELETE FROM `$this->tablename` $where";
		return $this->db->exec($sql);
	}
	/**
	 * 按给定的数据表的主键删除记录
	 *
	 * @param pk    字符串或数字，数据表主键的值。
	 */
	public function delPk($pk){
		
		$Pk = $this->db->escape($Pk);
		return $this->del(array($this->pk=>$pk));
	}
	/**
	 * 使用SQL语句进行查找操作，等于进行find，findAll等操作
	 *
	 * @param sql 字符串，需要进行查找的SQL语句
	 */
	public function findSql($sql,$limit = null){
		if(null != $limit)$sql = $this->db->setlimit($sql, $limit);
		return $this->db->getArray($sql);
	}
	public function find($sql){

		return $this->db->getArray($sql);
	}

	/**
	 * 执行SQL语句，相等于执行新增，修改，删除等操作。
	 *
	 * @param sql 字符串，需要执行的SQL语句
	 */
	public function runSql($sql){

		return $this->db->exec($sql);
	}
	/** 
	 * query是runSql的别名，向前兼容
	 */
	public function query($sql){

		return $this->runSql($sql);
	}
	/**
	 * 按表字段调整适合的字段
	 * @param rows    输入的表字段
	 */
	public function formatRow($rows)
	{
		$columns = $this->db->getTable($this->tablename);
		$newcol = array();
		foreach( $columns as $col ){
			$newcol[$col['Field']] = $col['Field'];
		}
		return array_intersect_key($rows,$newcol);
	}
}




/*
 * Pager
 * 数据分页类
 */
class Pager {

	private $model_obj = null;		//模型对象
	private $pageData = null;		//页码数据
	private $input_args = null;		//调用时输入的参数

	/**
	 * 函数式使用模型辅助类的输入函数
	 */
	public function __input(& $obj, $args){
		$this->model_obj = $obj;
		$this->input_args = $args;
		return $this;
	}
	/**
	 * 魔术函数，支持多重函数式使用类的方法
	 */
	public function __call($func_name, $func_args){
		if( ( 'findAll' == $func_name || 'findSql' == $func_name ) && 0 != $this->input_args[0]){
			return $this->runpager($func_name, $func_args);
		}elseif(method_exists($this,$func_name)){
			return call_user_func_array(array($this, $func_name), $func_args);
		}else{
			return call_user_func_array(array($this->model_obj, $func_name), $func_args);
		}
	}

	/**
	 * 获取分页数据
	 */
	public function getPager(){
		return $this->pageData;
	}

	/**
	 * 分页链接
	 */
	public function setUrl($vlaue){

		$control = (!isset($_GET['c'])||$_GET['c']==null)?$GLOBALS['C']['Common']['Control']:trim($_GET['c']);
		$action  = (!isset($_GET['a'])||$_GET['a']==null)?$GLOBALS['C']['Common']['Action']:trim($_GET['a']);
		$url ='/'.APP_FILE.'.php/'.$control.'/'.$action.'/p/'.$vlaue;
		return $url;

	}
	/**
	 * 生成分页数据
	 */
	private function runpager($func_name, $func_args){
		$this->pageData = null;
		if(!isset($_GET["p"]) || $_GET["p"] == null){
			$page = 1;
		}
		else{
			$page = $_GET["p"];
		}
		$pageSize = $this->input_args[0];
		if('findSql'==$func_name){
			$total_count = count($this->model_obj->findSql($func_args[0],$limit));
		}else{
			$total_count = $this->model_obj->findCount();
		}


		if($total_count > $pageSize){
			$total_page = ceil( $total_count / $pageSize );
			$page = min(intval(max($page, 1)), $total_count); // 对页码进行规范运算
			$this->pageData = array(
				"total_count" => $total_count,                                			 // 总记录数
				"page_size"   => $pageSize,                                    			 // 分页大小
				"total_page"  => $total_page,                                 			 // 总页数
				"first_page"  => 1,                                            			 // 第一页
				"prev_page"   => ( ( 1 == $page ) ? 1 : ($page - 1) ),        			 // 上一页
				"next_page"   => ( ( $page == $total_page ) ? $total_page : ($page + 1)),// 下一页
				"last_page"   => $total_page,                                 			 // 最后一页
				"current_page"=> $page,                                       			 // 当前页
				"all_pages"   => array()	                                 			 // 全部页码
			);
			for($i=1; $i <= $total_page; $i++)$this->pageData['all_pages'][] = $i;
			$limit = ($page - 1) * $pageSize . "," . $pageSize;
			if('findSql'==$func_name)$this->model_obj->db->setlimit($limit);
		}
		if('findSql'==$func_name){
			return $this->model_obj->findSql($func_args[0],$limit);
		}else{
			return $this->model_obj->findAll($sort,$limit);
		}
	}
}





/*
 * spCache
 * 函数和数据缓存实现
 */
class Cache {


	public $life_time = 3600;			//默认的数据生存期	 *
	private $model_obj = null;			//模型对象
	private $input_args = null;			//调用时输入的参数

	/**
	 * 函数式使用模型辅助类的输入函数
	 */
	public function __input(& $obj, $args){
		$this->model_obj = $obj;
		$this->input_args = $args;
		return $this;
	}

	/**
	 * 魔术函数，支持多重函数式使用类的方法
	 */
	public function __call($func_name, $func_args){
		if( isset($this->input_args[0]) && -1 == $this->input_args[0] )return $this->clear($this->model_obj, $func_name, $func_args);
		$cache_id = get_class($this->model_obj) . md5($func_name);
		if( null != $func_args )$cache_id .= md5(json_encode($func_args));
		if( $cache_file = cacheAccess('r', "sp_cache_{$cache_id}") )return unserialize( $cache_file );
		return $this->cache_obj($cache_id, call_user_func_array(array($this->model_obj, $func_name), $func_args), $this->input_args[0]);
	}

	/**
	 * 执行spModel子类对象的方法，并对返回结果进行缓存。
	 *
	 * @param obj    引用的spModel子类对象
	 * @param func_name    需要执行的函数名称
	 * @param func_args    函数的参数
	 * @param life_time    缓存生存时间
	 */
	public function cache_obj($cache_id, $run_result, $life_time = null ){
		if( null == $life_time )$life_time = $this->life_time;
		cacheAccess('w', "sp_cache_{$cache_id}", serialize($run_result), $life_time);
		if( $cache_list = cacheAccess('r', 'sp_cache_list') ){
			$cache_list = explode("\n",$cache_list);
			if( ! in_array( $cache_id, $cache_list ) )cacheAccess('w', 'sp_cache_list', join("\n", $cache_list) . $cache_id . "\n");
		}else{
			cacheAccess('w', 'sp_cache_list', $cache_id . "\n");
		}
		return $run_result;
	}
	/**
	 * 清除单个函数缓存的数据
	 *
	 * @param obj    引用的spModel子类对象
	 * @param func_name    需要执行的函数名称
	 * @param func_args    函数的参数，在默认不输入参数的情况下，将清除全部该函数生成的缓存。
	 * 如果func_args有设置，将只会清除该参数产生的缓存。
	 */

	public function clear(& $obj, $func_name, $func_args = null){
		$cache_id = get_class($obj) . md5($func_name);
		if( null != $func_args )$cache_id .= md5(json_encode($func_args));
		if( $cache_list = cacheAccess('r', 'sp_cache_list') ){
			$cache_list = explode("\n",$cache_list);
			$new_list = '';
			foreach( $cache_list as $single_item ){
				if( $single_item == $cache_id || ( null == $func_args && substr($single_item,0,strlen($cache_id)) == $cache_id ) ){
					cacheAccess('c', "sp_cache_{$single_item}");
				}else{
					$new_list .= $single_item. "\n";
				}
			}
			cacheAccess('w', 'sp_cache_list', substr($new_list,0,-1));
		}
		return TRUE;
	}

	/**
	 * 清除全部函数缓存的数据
	 */

	public function clear_all(){
		if( $cache_list = cacheAccess('r', 'sp_cache_list') ){
			$cache_list = explode("\n",$cache_list);
			foreach( $cache_list as $single_item )cacheAccess('c', "sp_cache_{$single_item}");
			cacheAccess('c', 'sp_cache_list');
		}
		return TRUE;
	}
}






/*
 * Filter数据过滤类
 */
class Filter{
	/**
	 * 添加'\'  转义过滤函数
	 * $force：强制转换
	 * $strip强制使用stripslashes函数
	 */
	public function unstr($string, $force = 0, $strip = 1) {
		if(!get_magic_quotes_gpc() || $force) {
			if(is_array($string)) {
				foreach($string as $key => $val) {
					$string[$key] = self::unstr($val, $force);
				}
			} else {
				$string = mysql_escape_string($strip ? stripslashes($string) : $string);
			}
		}
		return $string;
	}
	
	/**
	 * unhtml($value)过滤危险HTMl
	 */
	public function unhtml($str)
	{
		$farr = array(
        "/\s+/",                                                                      //过滤多余的空白
        "/<(\/?)(script|i?frame|style|html|body|title|link|meta|object|\?|\%)([^>]*?)>/isU", //过滤 <script 等可能引入恶意内容或恶意改变显示布局的代码,如果不需要插入flash等,还可以加入<object的过滤
        "/(<[^>]*)on[a-zA-Z]+\s*=([^>]*>)/isU",                                      //过滤javascript的on事件
		 
		);
		$tarr = array(
        " ",
        "＜\\1\\2\\3＞",           //如果要直接清除不安全的标签，这里可以留空
        "\\1\\2",
		);

		$str = preg_replace( $farr,$tarr,$str);
		return $str;
	}
	/**
	 * unsql($value)防SQL注入
	 */
	public function unsql($value) {
		$value = eregi_replace('select|insert|update|delete|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile','',$value);
		return $value;
	}
	/**
	 * unjs($value)过滤JS
	 */
	public function unjs($value) {
		$value = ereg_replace("[\r\n\t ]{1,}",' ',$value);
		$value = eregi_replace('script','ｓｃｒｉｐｔ',$value);
		$value = eregi_replace("<[/]{0,1}(link|meta|ifr|fra)[^>]*>",'',$value);
		return $value;
	}
	/**
	 * 检查字符串非空
	 */	 
	public function notnull($val, $right){return $right === ( strlen($val) > 0 );}
	/**
	 * 检查字符串是否小于指定长度
	 */
	public function minlength($val, $right){return $this->cn_strlen($val) >= $right;}
	/** 
	 * 内置验证器，检查字符串是否大于指定长度
	 * @param val    待验证字符串
	 * @param right    正确值
	 */
	public function maxlength($val, $right){return $this->cn_strlen($val) <= $right;}
	/**
	 * 检查字符串是否小于指定长度
	 */
	/** 
	 * 内置验证器，检查字符串是否等于另一个验证字段的值
	 * @param val    待验证字符串
	 * @param right    正确值
	 */
	public function equalto($val, $right){return $val == $this->checkvalues[$right];}
	/**
	 *检查字符串是否正确的时间格式
	 */
	public function istime($val, $right){$test = @strtotime($val);return $right == ( $test !== -1 && $test !== false );}
	/**
	 * 检查字符串是否正确的电子邮件格式
	 */
	public function isemail($val, $right){
		return $right == ( preg_match('/^[A-Za-z0-9]+([._\-\+]*[A-Za-z0-9]+)*@([A-Za-z0-9-]+\.)+[A-Za-z0-9]+$/', $val) != 0 );
	}
	/**
	 * 计算字符串长度，支持包括汉字在内的字符串
	 */
	public function cn_strlen($val){$i=0;$n=0;
		while($i<strlen($val)){$clen = ( strlen("快速") == 4 ) ? 2 : 3;
			if(preg_match("/^[".chr(0xa1)."-".chr(0xff)."]+$/",$val[$i])){$i+=$clen;}else{$i+=1;}$n+=1;}
		return $n;
	}

}
